﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Reflection;

namespace Kokomo.Mirror.CliMetadata
{
	public class ExceptionBlock
	{
		internal ExceptionBlock(
			int tryOffset,
			int tryLength
			)
		{
			this._handlerBlocks = new List<ExceptionHandlerBlock>();
			this.HandlerBlocks = new ReadOnlyCollection<ExceptionHandlerBlock>(this._handlerBlocks);
		}

		public int TryOffset { get; private set; }
		public int TryLength { get; private set; }
		public int TryEndOffset { get { return this.TryOffset + this.TryLength; } }
		public int BlockEndOffset { get; internal set; }

		private IList<ExceptionHandlerBlock> _handlerBlocks;
		public IList<ExceptionHandlerBlock> HandlerBlocks { get; private set; }

		internal void AddHandlerBlock(ExceptionHandlingClause clause)
		{
			this._handlerBlocks.Add(new ExceptionHandlerBlock(clause));
			this.BlockEndOffset = Math.Max(this.BlockEndOffset, clause.HandlerOffset + clause.HandlerLength);
		}

		public IList<ExceptionBlockMarker> GetMarkers()
		{
			List<ExceptionBlockMarker> markers = new List<ExceptionBlockMarker>(this.HandlerBlocks.Count + 2);

			markers.Add(new ExceptionBlockStartMarker(this.TryOffset));
			foreach (var handler in this.HandlerBlocks)
			{
				ExceptionHandlingClause clause = handler.Clause;
				switch (clause.Flags)
				{
					case ExceptionHandlingClauseOptions.Clause:
						markers.Add(new CatchBlockStartMarker(clause.HandlerOffset, clause.CatchType));
						break;
					case ExceptionHandlingClauseOptions.Fault:
						markers.Add(new FaultBlockStartMarker(clause.HandlerOffset));
						break;
					case ExceptionHandlingClauseOptions.Filter:
						markers.Add(new FilterBlockStartMarker(clause.HandlerOffset, clause.CatchType));
						break;
					case ExceptionHandlingClauseOptions.Finally:
						markers.Add(new FinallyBlockStartMarker(clause.HandlerOffset));
						break;
					default:
						break;
				}
			}

			markers.Add(new ExceptionBlockEndMarker(this.BlockEndOffset));

			return markers;
		}
	}
}
